home *** CD-ROM | disk | FTP | other *** search
- /*
- * vbitmap.cpp - Original code from Avery Lee's Virtual Dub
- *
- * Copyright (C) Alberto Vigata - ultraflask@yahoo.com - January 2000
- *
- * This file is part of FlasKMPEG, a free MPEG to MPEG/AVI converter
- *
- * FlasKMPEG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * FlasKMPEG is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Make; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-
-
- #include <crtdbg.h>
- #include <math.h>
-
-
- #include "convert.h"
- #include "VBitmap.h"
-
-
- #define FP_EPSILON (1e-30)
-
- extern "C" void __cdecl asm_resize_nearest(
- Pixel32 *dst,
- Pixel32 *src,
- long width,
- PixDim height,
- PixOffset dstpitch,
- PixOffset srcpitch,
- unsigned long xaccum,
- unsigned long yaccum,
- unsigned long xfrac,
- unsigned long yfrac,
- long xistep,
- PixOffset yistep);
-
- extern "C" void __cdecl asm_resize_bilinear(
- void *dst,
- void *src,
- long w,
- PixDim h,
- PixOffset dstpitch,
- PixOffset srcpitch,
- unsigned long xaccum,
- unsigned long yaccum,
- unsigned long xfrac,
- unsigned long yfrac,
- long xistep,
- PixOffset yistep,
- long precopy,
- long postcopy,
- void *srclimit);
-
- extern "C" void __cdecl asm_bitmap_xlat1(Pixel32 *dst, Pixel32 *src,
- PixOffset dpitch, PixOffset spitch,
- PixDim w,
- PixDim h,
- const Pixel8 *tbl);
-
- extern "C" void __cdecl asm_bitmap_xlat3(Pixel32 *dst, Pixel32 *src,
- PixOffset dpitch, PixOffset spitch,
- PixDim w,
- PixDim h,
- const Pixel32 *tbl);
-
- ///////////////////////////////////////////////////////////////////////////
-
- VBitmap::VBitmap(void *lpData, BITMAPINFOHEADER *bmih) throw() {
- init(lpData, bmih);
- }
-
- VBitmap::VBitmap(void *data, PixDim w, PixDim h, int depth) throw() {
- init(data, w, h, depth);
- }
-
- ///////////////////////////////////////////////////////////////////////////
-
- VBitmap& VBitmap::init(void *lpData, BITMAPINFOHEADER *bmih) throw() {
- data = (Pixel *)lpData;
- palette = (Pixel *)(bmih+1);
- depth = bmih->biBitCount;
- w = bmih->biWidth;
- h = bmih->biHeight;
- offset = 0;
- AlignTo4();
-
- return *this;
- }
-
- VBitmap& VBitmap::init(void *data, PixDim w, PixDim h, int depth) throw() {
- this->data = (Pixel32 *)data;
- this->palette = NULL;
- this->depth = depth;
- this->w = w;
- this->h = h;
- this->offset = 0;
- AlignTo8();
-
- return *this;
- }
-
- void VBitmap::MakeBitmapHeader(BITMAPINFOHEADER *bih) const throw() {
- bih->biSize = sizeof(BITMAPINFOHEADER);
- bih->biBitCount = depth;
- bih->biPlanes = 1;
- bih->biCompression = BI_RGB;
-
- if (pitch == ((w*bih->biBitCount + 31)/32) * 4)
- bih->biWidth = w;
- else
- bih->biWidth = pitch*8 / depth;
-
- bih->biHeight = h;
- bih->biSizeImage = pitch*h;
- bih->biClrUsed = 0;
- bih->biClrImportant = 0;
- bih->biXPelsPerMeter = 0;
- bih->biYPelsPerMeter = 0;
- }
-
- void VBitmap::AlignTo4() throw() {
- pitch = PitchAlign4();
- modulo = Modulo();
- size = Size();
- }
-
- void VBitmap::AlignTo8() throw() {
- pitch = PitchAlign8();
- modulo = Modulo();
- size = Size();
- }
-
- ///////////////////////////////////////////////////////////////////////////
-
- bool VBitmap::dualrectclip(PixCoord& x2, PixCoord& y2, const VBitmap *src, PixCoord& x1, PixCoord& y1, PixDim& dx, PixDim& dy) const throw() {
- if (dx == -1) dx = src->w;
- if (dy == -1) dy = src->h;
-
- // clip to source bitmap
-
- if (x1 < 0) { dx+=x1; x2-=x1; x1=0; }
- if (y1 < 0) { dy+=y1; y2-=y1; y1=0; }
- if (x1+dx > src->w) dx=src->w-x1;
- if (y1+dy > src->h) dy=src->h-y1;
-
- // clip to destination bitmap
-
- if (x2 < 0) { dx+=x2; x1-=x2; x2=0; }
- if (y2 < 0) { dy+=y2; y1-=y2; y2=0; }
- if (x2+dx > w) dx=w-x2;
- if (y2+dy > h) dy=h-y2;
-
- // anything left to blit?
-
- if (dx<=0 || dy<=0)
- return false;
-
- return true;
- }
-
- ///////////////////////////////////////////////////////////////////////////
-
- void VBitmap::BitBlt(PixCoord x2, PixCoord y2, const VBitmap *src, PixDim x1, PixDim y1, PixDim dx, PixDim dy) const throw() {
- static void (*converters[3][3])(void *dest, long dest_pitch, void *src, long src_pitch, long width, long height) = {
- { DIBconvert_16_to_16, DIBconvert_24_to_16, DIBconvert_32_to_16, },
- { DIBconvert_16_to_24, DIBconvert_24_to_24, DIBconvert_32_to_24, },
- { DIBconvert_16_to_32, DIBconvert_24_to_32, DIBconvert_32_to_32, },
- };
-
- Pixel *dstp, *srcp;
-
- _ASSERT(depth >= 16); // we only blit to 16/24/32
-
- if (!dualrectclip(x2, y2, src, x1, y1, dx, dy))
- return;
-
- // compute coordinates
-
- srcp = src->Address(x1, y1+dy-1);
- dstp = Address(x2, y2+dy-1);
-
- // are we blitting from an 8-bit bitmap?
-
- //CHECK_FPU_STACK
-
- if (src->depth == 8)
- switch(depth) {
- case 32:
- DIBconvert_8_to_32(dstp, pitch, srcp, src->pitch, dx, dy, src->palette);
- break;
- case 24:
- DIBconvert_8_to_24(dstp, pitch, srcp, src->pitch, dx, dy, src->palette);
- break;
- case 16:
- DIBconvert_8_to_16(dstp, pitch, srcp, src->pitch, dx, dy, src->palette);
- break;
- }
- else {
- converters[depth/8-2][src->depth/8-2](dstp, pitch, srcp, src->pitch, dx, dy);
- }
-
- //CHECK_FPU_STACK
- }
-
- void VBitmap::BitBltDither(PixCoord x2, PixCoord y2, const VBitmap *src, PixDim x1, PixDim y1, PixDim dx, PixDim dy, bool to565) const throw() {
-
- // Right now, we can only dither 32->16
-
- if (src->depth != 32 || depth != 16) {
- BitBlt(x2, y2, src, x1, y1, dx, dy);
- return;
- }
-
- // Do the blit
-
- Pixel *dstp, *srcp;
-
- if (!dualrectclip(x2, y2, src, x1, y1, dx, dy))
- return;
-
- // compute coordinates
-
- srcp = src->Address(x1, y1+dy-1);
- dstp = Address(x2, y2+dy-1);
-
- // do the blit
-
- //CHECK_FPU_STACK
-
- if (to565)
- DIBconvert_32_to_16_565_dithered(dstp, pitch, srcp, src->pitch, dx, dy);
- else
- DIBconvert_32_to_16_dithered(dstp, pitch, srcp, src->pitch, dx, dy);
-
- //CHECK_FPU_STACK
- }
-
- void VBitmap::BitBlt565(PixCoord x2, PixCoord y2, const VBitmap *src, PixDim x1, PixDim y1, PixDim dx, PixDim dy) const throw() {
-
- // Right now, we can only convert 32->16/565
-
- if (src->depth != 32 || depth != 16) {
- BitBlt(x2, y2, src, x1, y1, dx, dy);
- return;
- }
-
- // Do the blit
-
- Pixel *dstp, *srcp;
-
- if (!dualrectclip(x2, y2, src, x1, y1, dx, dy))
- return;
-
- // anything left to blit?
-
- if (dx<=0 || dy<=0) return;
-
- // compute coordinates
-
- srcp = src->Address(x1, y1+dy-1);
- dstp = Address(x2, y2+dy-1);
-
- // do the blit
-
- //CHECK_FPU_STACK
-
- DIBconvert_32_to_16_565(dstp, pitch, srcp, src->pitch, dx, dy);
-
- //CHECK_FPU_STACK
- }
-
- bool VBitmap::BitBltXlat1(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy, const Pixel8 *tbl) const throw() {
- if (depth != 32)
- return false;
-
- if (!dualrectclip(x2, y2, src, x1, y1, dx, dy))
- return false;
-
- // do the translate
-
- asm_bitmap_xlat1(
- this->Address32(x2, y2+dy-1)+dx,
- src ->Address32(x1, y1+dy-1)+dx,
- this->pitch,
- src->pitch,
- -4*dx, dy, tbl);
-
- return true;
- }
-
- bool VBitmap::BitBltXlat3(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy, const Pixel32 *tbl) const throw() {
- if (depth != 32)
- return false;
-
- if (!dualrectclip(x2, y2, src, x1, y1, dx, dy))
- return false;
-
- // do the translate
-
- asm_bitmap_xlat3(
- this->Address32(x2, y2+dy-1)+dx,
- src ->Address32(x1, y1+dy-1)+dx,
- this->pitch,
- src->pitch,
- -4*dx, dy, tbl);
-
- return true;
- }
-
- ///////////////////////////////////////////////////////////////////////////
-
- static __int64 sbnf_correct(double x, double y) {
- __int64 v;
-
- x = x * 4294967296.0;
-
- if (x < 0.0)
- v = (__int64)(x - 0.5);
- else
- v = (__int64)(x + 0.5);
-
- if (y<0.0 && v) ++v;
- if (y>0.0 && v) --v;
-
- return v;
- }
-
- bool VBitmap::StretchBltNearestFast(PixCoord x2, PixCoord y2, PixDim dx, PixDim dy,
- const VBitmap *src, double x1, double y1, double dx1, double dy1) const throw() {
-
- // No format conversions!!
-
- if (src->depth != depth)
- return false;
-
- // Right now, only do 32-bit stretch. (24-bit is a pain, 16-bit is slow.)
-
- if (depth != 32)
- return false;
-
- // Funny values?
-
- if (dx <= 0 || dy <= 0)
- return false;
-
- // Check for destination clipping and abort if so.
-
- if (x2 < 0 || y2 < 0 || x2+dx > w || y2+dy > h)
- return false;
-
- // Check for source clipping. Trickier, since we permit source flips.
-
- if (x1 < 0.0 || y1 < 0.0 || x1+dx1 < 0.0 || y1+dy1 < 0.0)
- return false;
-
- if (x1 > src->w || y1 > src->h || x1+dx1 > src->w || y1+dy1 > src->h)
- return false;
-
- // Compute step values.
-
- __int64 xfrac64, yfrac64, xaccum64, yaccum64;
- unsigned long xfrac, yfrac;
- int xistep;
- PixOffset yistep;
-
- /* xfrac64 = sbnf_correct(dx1, dx1) / dx; // round toward zero to avoid exceeding buffer
- yfrac64 = sbnf_correct(dy1, dy1) / dy;*/
- xfrac64 = dx1*4294967296.0 / dx; // round toward zero to avoid exceeding buffer
- yfrac64 = dy1*4294967296.0 / dy;
-
- xfrac = (unsigned long)xfrac64;
- yfrac = (unsigned long)yfrac64;
-
- xistep = (long)(xfrac64 >> 32); // round toward -oo
- yistep = (long)(yfrac64 >> 32) * src->pitch;
-
- xaccum64 = sbnf_correct(x1, -dx1) + xfrac64/2;
- yaccum64 = sbnf_correct(y1, -dy1) + yfrac64/2;
-
- // Call texturing routine.
-
- asm_resize_nearest(
- Address32i(x2, y2) + dx, // destination pointer, right side
- src->Address32i((long)(xaccum64>>32), (long)(yaccum64>>32)),
- -dx*4,
- dy,
- pitch,
- src->pitch,
- (unsigned long)xaccum64,
- (unsigned long)yaccum64,
- xfrac,
- yfrac,
- xistep,
- yistep);
-
- return true;
- }
-
- bool VBitmap::StretchBltBilinearFast(PixCoord x2, PixCoord y2, PixDim dx, PixDim dy,
- const VBitmap *src, double x1, double y1, double dx1, double dy1) const throw() {
-
- // No format conversions!!
-
- if (src->depth != depth)
- return false;
-
- // Right now, only do 32-bit stretch. (24-bit is a pain, 16-bit is slow.)
-
- if (depth != 32)
- return false;
-
- // Funny values?
-
- if (dx <= 0 || dy <= 0)
- return false;
-
- // Check for destination clipping and abort if so.
-
- if (x2 < 0 || y2 < 0 || x2+dx > w || y2+dy > h)
- return false;
-
- // Check for source clipping. Trickier, since we permit source flips.
-
- if (x1 < 0.0 || y1 < 0.0 || x1+dx1 < 0.0 || y1+dy1 < 0.0)
- return false;
-
- if (x1 > src->w || y1 > src->h || x1+dx1 > src->w || y1+dy1 > src->h)
- return false;
-
- // Compute step values.
-
- __int64 xfrac64, yfrac64, xaccum64, yaccum64;
- unsigned long xfrac, yfrac;
- int xistep;
- PixOffset yistep;
-
- xfrac64 = (fabs(dx1)<1.0 ? 0.0 : dx1<0.0 ? dx1+1.0 : dx1-1.0)*4294967296.0 / (dx-1); // round toward zero to avoid exceeding buffer
- yfrac64 = (fabs(dy1)<1.0 ? 0.0 : dy1<0.0 ? dy1+1.0 : dy1-1.0)*4294967296.0 / (dy-1);
-
- xfrac = (unsigned long)xfrac64;
- yfrac = (unsigned long)yfrac64;
-
- xistep = (long)(xfrac64 >> 32); // round toward -oo
- yistep = (long)(yfrac64 >> 32) * src->pitch;
-
- xaccum64 = (__int64)floor(x1*4294967296.0 + 0.5);
- yaccum64 = (__int64)floor(y1*4294967296.0 + 0.5);
-
- if (dx1<0)
- --xaccum64;
- if (dy1<0)
- --yaccum64;
-
- // Compute addresses.
-
- Pixel32 *srcp = src->Address32i((long)(xaccum64>>32), (long)(yaccum64>>32));
- Pixel32 *dstp = Address32i(x2, y2);
-
- // Determine border sizes. We have to copy pixels when xaccum >= (w-1)<<32
- // or yaccum >= (h-1)<<32;
-
- int xprecopy=0, xpostcopy=0;
- __int64 xborderval, yborderval;
-
- xborderval = ((__int64)(src->w-1)<<32);
- yborderval = ((__int64)(src->h-1)<<32);
-
- if (xfrac64 < 0) {
- if (xaccum64 >= xborderval) {
- xprecopy = (xaccum64 - (xborderval-1) + xfrac64 - 1) / xfrac64 + 1;
- }
-
- if (xprecopy > dx)
- xprecopy = dx;
-
- } else {
- if (xaccum64 + xfrac64*(dx-1) >= xborderval) {
- xpostcopy = dx - ((xborderval - xaccum64 - 1)/xfrac64 + 1);
- }
-
- if (xpostcopy > dx)
- xpostcopy = dx;
- }
-
- // Call texturing routine.
-
- if (dy) {
- dx -= xprecopy + xpostcopy;
-
- asm_resize_bilinear(
- Address32i(x2, y2) + (dx+xprecopy), // destination pointer, right side
- src->Address32i((long)(xaccum64>>32), (long)(yaccum64>>32)),
- -dx*4,
- dy,
- pitch,
- src->pitch,
- (unsigned long)xaccum64,
- (unsigned long)yaccum64,
- xfrac,
- yfrac,
- xistep,
- yistep,
- -xprecopy*4,
- -xpostcopy*4,
- src->Address32i(0, src->h-1));
- }
-
- return true;
- }
-
- bool VBitmap::RectFill(PixCoord x, PixCoord y, PixDim dx, PixDim dy, Pixel32 c) const throw() {
-
- if (depth != 32)
- return false;
-
- // Do the blit
-
- Pixel32 *dstp;
-
- if (dx == -1) dx = w;
- if (dy == -1) dy = h;
-
- // clip to destination bitmap
-
- if (x < 0) { dx+=x; x=0; }
- if (y < 0) { dy+=y; y=0; }
- if (x+dx > w) dx=w-x;
- if (y+dy > h) dy=h-y;
-
- // anything left to fill?
-
- if (dx<=0 || dy<=0) return false;
-
- // compute coordinates
-
- dstp = Address32(x, y+dy-1);
-
- // do the fill
-
- do {
- PixDim dxt = dx;
- Pixel32 *dst2 = dstp;
-
- do {
- *dst2++ = c;
- } while(--dxt);
-
- dstp = (Pixel32 *)((char *)dstp + pitch);
- } while(--dy);
-
- return true;
- }
-
-